package com.newupbank.schedule.mail.task;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.newupbank.schedule.mail.vo.MailConfigVO;
import com.newupbank.schedule.mail.vo.MailReceiverVO;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.MailException;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.IOException;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Component
public class SendMailMsg {
    private static final Logger logger = LoggerFactory.getLogger(SendMailMsg.class);

    @Value("${spring.mail.properties.mail.smtp.timeout}")
    private int timeout;

    @Value("${mail.default.content}")
    private String mailContent;

    private JavaMailSenderImpl createMailSender(MailConfigVO mailConfigVO) {
        JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
        mailSender.setHost(mailConfigVO.getHost());
        mailSender.setPort(mailConfigVO.getPort());
        mailSender.setUsername(mailConfigVO.getFromMail());
        mailSender.setPassword(mailConfigVO.getAuthCode());
        mailSender.setDefaultEncoding("Utf-8");
        Properties p = new Properties();
        p.setProperty("mail.smtp.timeout", timeout + "");
        p.setProperty("mail.smtp.auth", "true");
        mailSender.setJavaMailProperties(p);
        return mailSender;
    }

    /**
     * 从数据库读取
     *
     * @param mailConfigVO
     * @param message
     */
    public void sendMessage(MailConfigVO mailConfigVO, String message) {

        try {
            List<MailReceiverVO> mailReceiverVOList = mailConfigVO.getToMails();
            if (CollectionUtil.isEmpty(mailReceiverVOList)) {
                logger.warn("sendMessage===>mailReceiverVOList is empty!!!");
                return;
            }
            JavaMailSender mailSender = createMailSender(mailConfigVO);
            MimeMessage mimeMessage = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(mimeMessage);
            helper.setFrom(mailConfigVO.getFromMail());//发送者邮件邮箱
            helper.setSubject(mailConfigVO.getSubject());//发件主题
            helper.setText(message, false);//发件内容

            sendByCycle(mailReceiverVOList, mailSender, helper);
            // sendByMultiThread(mailReceiverVOList, mailSender, helper);

            logger.info("SendMailMsg--->sendMessage is ok;mailConfigVO:{};message:{}", JSON.toJSONString(mailConfigVO), message);
        } catch (Exception e) {
            logger.error("SendMailMsg--->sendMessage is error;subject:{};message:{}", mailConfigVO.getSubject(), message);
        }

    }

    // 逐个循环发送
    private void sendByCycle(List<MailReceiverVO> mailReceiverVOList, JavaMailSender mailSender, MimeMessageHelper helper) {
        for (MailReceiverVO mailReceiverVO : mailReceiverVOList) {
            try {
                helper.setTo(mailReceiverVO.getToMail());//收邮件者邮箱
                mailSender.send(helper.getMimeMessage());//发送邮件
                logger.info("sendByCycle oneByOne is ok; toMail={},name={}", mailReceiverVO.getToMail(), mailReceiverVO.getName());
            } catch (MailException | MessagingException e) {
                // 发生异常继续发送下一个
                logger.error("sendByCycle oneByOne is error; toMail={},name={}", mailReceiverVO.getToMail(), mailReceiverVO.getName(), e);
            }
        }
    }

    // 多线程发送,多个人逐个发送[目前邮箱暂不支持并发]
    private void sendByMultiThread(List<MailReceiverVO> mailReceiverVOList, JavaMailSender mailSender, MimeMessageHelper helper) {
        ExecutorService executorService = Executors.newFixedThreadPool(mailReceiverVOList.size());
        for (MailReceiverVO mailReceiverVO : mailReceiverVOList) {
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    try {
                        helper.setTo(mailReceiverVO.getToMail());//收邮件者邮箱
                        mailSender.send(helper.getMimeMessage());//发送邮件
                        logger.info("sendByMultiThread oneByOne is ok; toMail={},name={}", mailReceiverVO.getToMail(), mailReceiverVO.getName());
                    } catch (MailException | MessagingException e) {
                        // 发生异常继续发送下一个
                        logger.error("sendByMultiThread oneByOne is error; toMail={},name={}", mailReceiverVO.getToMail(), mailReceiverVO.getName(), e);
                    }
                }
            };
            executorService.execute(runnable);
        }
        executorService.shutdown();
    }

    /**
     * 远程获取要发送的信息
     */
    public String getOneMessage(String contentFromUrl) {
        try {
            //创建客户端对象
            HttpClient client = HttpClients.createDefault();
            /*创建地址 https://du.shadiao.app/api.php*/
            HttpGet get = new HttpGet(contentFromUrl);
            //发起请求，接收响应对象
            HttpResponse response = client.execute(get);
            //获取响应体，响应数据是一种基于HTTP协议标准字符串的对象
            //响应体和响应头，都是封装HTTP协议数据。直接使用可能出现乱码或解析错误
            HttpEntity entity = response.getEntity();
            //通过HTTP实体工具类，转换响应体数据
            String responseString = EntityUtils.toString(entity, "utf-8");
            // 如果请求网站没查询都就取默认值
            responseString = responseString == null ? mailContent : responseString;
            logger.info("SendMailMsg--->getOneMessage is ok;message:{}", responseString);
            return responseString;
        } catch (IOException e) {
            logger.error("SendMailMsg--->getOneMessage is fail;网站获取句子失败");
            throw new RuntimeException("网站获取句子失败");
        }
    }
}
